package net.sunbeta.test.util;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Utility class to convert nulls into values and values into nulls
 */
public class NullUtils
{
	public static final String[] EMPTY_STRING_ARRAY = new String[]{};
	
	public static <T> T nullIf(T object,  boolean makeNull)
	{
		if(makeNull)
		{
			return null;
		}
		
		return object;
	}
	
	public static <T> T ifNull(T object,  T replacement)
	{
		if(object == null)
		{
			return replacement;
		}
		
		return object;
	}
	
	public static <T> T ifNull(T object,  T... replacements)
	{
		if(object == null)
		{
			for(T replacement : replacements)
			{
				if(replacement != null)
				{
					return replacement;
				}
			}
		}
		
		return object;
	}
	
	public static <T> T ifNull(T object, Class<T> interfaze, Class<?>... otherInterfaces)
	{
		final ClassLoader classLoader = ifNull(Thread.currentThread().getContextClassLoader(), NullUtils.class.getClassLoader());
		
		int otherSize = otherInterfaces == null ? 0 : otherInterfaces.length;
		Class<?>[] interfaces = new Class[otherSize + 1];
		interfaces[0] = interfaze;
		
		if(otherSize > 0)
		{
			System.arraycopy(otherInterfaces, 0, interfaces, 1, otherSize);
		}
		
		return interfaze.cast(
				Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler()
				{
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable
					{
						return null;
					}
				})
				);
	}
	
	public static String[] ifNull(String[] data)
	{
		if(data == null)
		{
			return EMPTY_STRING_ARRAY;
		}
		
		return data;
	}
	
	public static <T> Collection<T> ifNull(Collection<T> data)
	{
		if(data == null)
		{
			return emptyList();
		}
		
		return data;
	}
	
	public static <T extends Collection<?>> T nullIfEmpty(T collection)
	{
		if(collection == null)
		{
			return null;
		}
		
		if(collection.size() < 1)
		{
			return null;
		}
		
		return collection;
	}
	
	public static <T> List<T> ifNull(List<T> data)
	{
		if(data == null)
		{
			return emptyList();
		}
		
		return data;
	}
	
	public static <T> Set<T> ifNull(Set<T> data)
	{
		if(data == null)
		{
			return emptySet();
		}
		
		return data;
	}
	
	public static <T> Set<T> ifEmpty(Set<T> data)
	{
		if(data == null)
		{
			return null;
		}
		
		if(data.size() == 0)
		{
			return null;
		}
		
		return data;
	}
	
	public static <K,V> Map<K,V> ifNull(Map<K,V> data)
	{
		if(data == null)
		{
			return emptyMap();
		}
		
		return data;
	}

	public static String IfNull(String object)
	{
		return ifNull(object, "");
	}
}
